function detectAttach(elem: Node) {
	const fn = monitorAttachNode.get(elem);
	fn?.();
	elem.childNodes.forEach((node) => {
		detectAttach(node);
	});
}

function detectDetach(elem: Node) {
	const fn = monitorDetachNode.get(elem);
	fn?.();
	elem.childNodes.forEach((node) => {
		detectDetach(node);
	});
}

const observer = new MutationObserver(function (mutationsList) {
	mutationsList.forEach(function (record) {
		record.addedNodes.forEach(function (node) {
			detectAttach(node);
		});
		record.removedNodes.forEach(function (node) {
			detectDetach(node);
		});
	});
});

const monitorAttachNode = new WeakMap<Node, () => void>();
const monitorDetachNode = new WeakMap<Node, () => void>();

observer.observe(document.documentElement, { subtree: true, childList: true, attributes: false, characterData: false });

export function addAttachListener(elem: Node | Node[], eventHandler: () => void) {
	[elem].flat(1).forEach((el) => {
		monitorAttachNode.set(el, eventHandler);
	});
}

export function removeAttachListener(elem: Node | Node[]) {
	[elem].flat(1).forEach((el) => {
		monitorAttachNode.delete(el);
	});
}

export function addDetachListener(elem: Node | Node[], eventHandler: () => void) {
	[elem].flat(1).forEach((el) => {
		monitorDetachNode.set(el, eventHandler);
	});
}

export function removeDetachListener(elem: Node | Node[]) {
	[elem].flat(1).forEach((el) => {
		monitorDetachNode.delete(el);
	});
}
